/* The file is saved in UTF-8 codepage.
 * Check: «Stereotype», Section mark-§, Copyright-©, Alpha-α, Beta-β, Smile-☺
 */
package cz.pecinovsky.english.lootp.utility;




import cz.pecinovsky.english.lootp.utility.IO_Test       .IO;
////////////////////////////////////////////////////////////////////////////////
//%%+  +++++ End of ignored starting test - place for imports +++++

import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import java.util.HashMap;
import java.util.Map;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

//%X+ xxxxx Start of the ovejumped text with declaration of the envelope xxxxx
/*******************************************************************************
 *<pre>
 * Předchozí:   Není - toto_je_nově_definovaná_třída
 *              Ttt v projektu Ppp
 * Následující: Prozatím není
 *
 * Projekt  Ppp
 *   + Přidáno
 *   - Odebráno
 *   ~ Změněno
 *</pre>
 *
 * @author Rudolf PECINOVSKÝ
 * @version 6.03.2017 — 2010-11-08
 */
public class IO_Test
{    private IO_Test() {}   static
////////////////////////////////////////////////////////////////////////////////
//%X- ----- End of the ovejumped text with declaration of the envelope -----

/*******************************************************************************
 * Knihovní třída {@code IO} obsahuje sadu metod
 * pro jednoduchý vstup a výstup prostřednictvím dialogových oken
 * spolu s metodou zastavující běh programu na daný počet milisekund
 * a metodu převádějící texty na ASCII jednoduchým odstraněním diakritiky.
 *
 * @author   Rudolf PECINOVSKÝ
 * @version 6.02 - 2010-11-04
 */
public final class IO //implements IIO
{
//== CONSTANT CLASS ATTRIBUTES =================================================

    /** Přepravka pro nulové veikosti okrajů. */
    private static final Insets NULOVÝ_OKRAJ = new Insets(0, 0, 0, 0);

    /** Rozdíl mezi tlouštkou rámečku okna ohlašovanou před a po
     *  volání metody {@link #setResizable(boolean)}.
     *  Tento rozdíl ve Windows ovlivňuje nastavení velikosti a pozice.
     *  Při {@code setResizable(true)} jsou jeho hodnoty větší,
     *  a proto se spočte se jako "true" - "false". */
    private static final Insets INSETS_DIF;

    /** Informace o tom, budou-li se opravovat pozice a rozměry oken. */
    private static final boolean OPRAVOVAT;



//== VARIABLE CLASS ATTRIBUTES =================================================

    /** Delegát starající se o provádění metod. */
    private static IIO delegát;


//== STATIC CONSTRUCTOR (CLASS INITIALIZER, STATIC INICITALIZING BLOCK) ======== 

    /** Windows Vista + Windows 7 se neumějí dohodnout s Javou na skutečné
     *  velikosti oken a jejich rámů a v důsledku toho nefunguje správně
     *  ani umísťování oken na zadané souřadnice.
     *  Následující statický konstruktor se snaží zjistit chování aktuálního
     *  operačního systému a podle toho připravit potřebné korekce.
     *  Doufejme, že záhy přestane být potřeba.
     */
    static {
        String os = System.getProperty("os.name");
        if (os.startsWith("Windows")) {
            JFrame okno = new JFrame();
            okno.setLocation(-1000, -1000);
            okno.setResizable(true);
            okno.pack();
            Insets insTrue  = okno.getInsets();
//            System.out.println("Insets - resizable=true:  " + insTrue);
            okno.setResizable(false);
            Insets insFalse = okno.getInsets();
//            System.out.println("Insets - resizable=false: " + insFalse);
            Insets insets;
            insets = new Insets(insTrue.top    - insFalse.top,
                                insTrue.left   - insFalse.left,
                                insTrue.bottom - insFalse.bottom,
                                insTrue.right  - insFalse.right);
            if (NULOVÝ_OKRAJ.equals(insets)) {
                //Nevěřím mu, určitě kecá
                int úbytek = (insTrue.left == 8)  ?  5  :  1;
                insets = new Insets(úbytek, úbytek, úbytek, úbytek);
            }
            INSETS_DIF = insets;
            OPRAVOVAT = true;
//            OPRAVOVAT = ! NULOVÝ_OKRAJ.equals(INSETS_DIF);
        }
        else {
            INSETS_DIF = NULOVÝ_OKRAJ;
            OPRAVOVAT  = false;
        }
//        System.out.println("INSETS_DIF: " + INSETS_DIF +
//                         "\nOPRAVOVAT:  " + OPRAVOVAT + "\n");
    }


    /** Statický inicializační blok mající na starosti přepínání
     *  mezi běžným a testovacím režimem zavádění této třídy.  */
    static {
        String klíč = "rup.io.testmode";
        if (System.getProperty(klíč) != null &&
            Boolean.valueOf(System.getProperty(klíč))) {
            delegát = new IOTestovací();
        } else {
            delegát = new IOBěžné();
        }
    }



//== CONSTANT INSTANCE ATTRIBUTES ==============================================
//== VARIABLE INSTANCE ATTRIBUTES ==============================================
//== CLASS GETTERS AND SETTERS =================================================
//== OTHER NON-PRIVATE CLASS METHODS ===========================================

    /***************************************************************************
     * Počká zadaný počet milisekund.
     * Na přerušení nijak zvlášť nereaguje - pouze skončí dřív.
     * Před tím však nastaví příznak, aby volající metoda poznala,
     * že vlákno bylo žádáno o přerušení.
     *
     * @param milisekund   Počet milisekund, po něž se má čekat.
     */
    public static void hold(int milisekund)
    {
        delegát.hold(milisekund);
    }


    /***************************************************************************
     * Při splnění zadané podmínky otevře dialogové okno s nápisem KONEC
     * a po jeho zavření ukončí program.
     *
     * @param platí  Podmínka, po jejímž splnění se program ukončí
     */
    public static void endIf(boolean platí)
    {
        delegát.endIf(platí);
    }


    /***************************************************************************
     * Při splnění zadané podmínky otevře dialogové okno se zadanou zprávou
     * a po jeho zavření ukončí program.
     *
     * @param platí  Podmínka, po jejímž splnění se program ukončí
     * @param inform Zpráva vypisovaná v dialogovém okně. Je-li {@code null}
     *               nebo prázdný řetězec, vypíše <b>{@code KONEC}</b>.
     */
    public static void endIf(boolean platí, String zpráva)
    {
        delegát.endIf(platí, zpráva);
    }


    /***************************************************************************
     * Zbaví zadaný text diakritických znamének; současně ale odstraní také
     * všechny další znaky nespadající do tabulky ASCII.
     *
     * @param text Text určený k "odháčkování"
     * @return  "Odháčkovaný" text
     */
    public static String removeAccents(String text)
    {
        return delegát.removeAccents(text);
    }


    /***************************************************************************
     * Nastaví pozici příštího dialogového okna.
     *
     * @param x  Vodorovná souřadnice
     * @param y  Svislá souřadnice
     */
    public static void setDialogsPosition(int x, int y)
    {
       delegát.setDialogsPosition(x, y);
    }


    /***************************************************************************
     * Zobrazí dialogové okno se zprávou a umožní uživateli odpovědět
     * ANO nebo NE. Vrátí informaci o tom, jak uživatel odpověděl.
     * Neodpoví-li a zavře dialog, ukončí program.
     *
     * @param dotaz   Zobrazovaný text otázky.
     * @return <b>{@code true}</b> Odpověděl-li uživatel <b>ANO</b>,
     *         <b>{@code false}</b> odpověděl-li <b>NE</b>
     */
    public static boolean confirm(Object dotaz)
    {
        return delegát.confirm(dotaz);
    }


    /***************************************************************************
     * Zobrazí dialogové okno s výzvou k zadání reálné hodoty;
     * při zavření okna zavíracím tlačítkem ukončí aplikaci.
     *
     * @param výzva        Text, který se uživateli zobrazí.
     * @param doubleImpl   Implicitní hodnota.
     * @return Uživatelem zadaná hodnota, resp. potvrzená implicitní hodnota.
     */
    public static double enter(Object výzva, double doubleImpl)
    {
        return delegát.enter(výzva, doubleImpl);
    }


    /***************************************************************************
     * Zobrazí dialogové okno s výzvou k zadání celočíselné hodoty;
     * při zavření okna nebo stisku tlačítka Cancel ukončí aplikaci.
     *
     * @param výzva     Text, který se uživateli zobrazí.
     * @param intImpl   Implicitní hodnota.
     * @return Uživatelem zadaná hodnota, resp. potvrzená implicitní hodnota.
     */
    public static int enter(Object výzva, int intImpl)
    {
        return delegát.enter(výzva, intImpl);
    }


    /***************************************************************************
     * Zobrazí dialogové okno s výzvou k zadání textové hodoty;
     * při zavření okna nebo stisku tlačítka Cancel ukončí aplikaci.
     *
     * @param výzva        Text, který se uživateli zobrazí.
     * @param stringImpl   Implicitní hodnota.
     * @return Uživatelem zadaná hodnota, resp. potvrzená implicitní hodnota.
     */
    public static String enter(Object výzva, String stringImpl)
    {
        return delegát.enter(výzva, stringImpl);
    }


    /***************************************************************************
     * Zobrazí dialogové okno se zprávou a počká, až je uživatel odklepne;
     * při zavření okna ukončí aplikaci.
     *
     * @param text   Zobrazovaný text.
     */
    public static void inform(Object text)
    {
        delegát.inform(text);
    }



//##############################################################################
//== CONSTUCTORS AND FACTORY METHODS ===========================================

    /***************************************************************************
     * Třída IO je knihovní třídou a proto není určena k tomu,
     * aby měla nějaké instance.
     */
    private IO() {}


//== ABSTRACT METHODS ==========================================================
//== INSTANCE GETTERS AND SETTERS ==============================================
//== OTHER NON-PRIVATE INSTANCE METHODS ========================================
//== PRIVATE AND AUXILIARY CLASS METHODS =======================================
//== PRIVATE AND AUXILIARY INSTANCE METHODS ====================================
//== EMBEDDED TYPES AND INNER CLASSES ==========================================

    /***************************************************************************
     * Třída {@code Correction} je knihovní třídou poskytující metody
     * pro opravy nejrůznějších nesrovnalostí týkajících se práce
     * s grafickým vstupem a výstupem.
     */
    public static class Correction
    {
    //== KONSTANTNÍ ATRIBUTY TŘÍDY =============================================
    //== PROMĚNNÉ ATRIBUTY TŘÍDY ===============================================
    //== STATICKÝ INICIALIZAČNÍ BLOK - STATICKÝ KONSTRUKTOR ====================
    //== KONSTANTNÍ ATRIBUTY INSTANCÍ ==========================================
    //== PROMĚNNÉ ATRIBUTY INSTANCÍ ============================================
    //== PŘÍSTUPOVÉ METODY VLASTNOSTÍ TŘÍDY ====================================
    //== OSTATNÍ NESOUKROMÉ METODY TŘÍDY =======================================

        /***********************************************************************
         * Ve Windows 7 používajících definuje Java jinou velikost okna,
         * než odpovídá velikosti panelu obrázku.
         *
         * @param cont   Kontejner, jehož rozměry upravujeme
         */
        public static void windowLocation(Container cont)
        {
            Point  loc;
            if (OPRAVOVAT) {
                loc = cont.getLocation();
                cont.setLocation(loc.x + INSETS_DIF.left,
                                 loc.y + INSETS_DIF.top);
            }
        }


        /***********************************************************************
         * Ve Windows 7 definuje Java jinou velikost okna,
         * než odpovídá velikosti panelu obrázku.
         *
         * @param cont     Kontejner, jehož rozměry upravujeme
         */
        public static void windowSize(Container cont)
        {
            Dimension dim;
            if (OPRAVOVAT) {
                dim = cont.getSize();
                cont.setSize(dim.width - INSETS_DIF.left - INSETS_DIF.right,
                             dim.height- INSETS_DIF.top  - INSETS_DIF.bottom);
            }
        }



    //##########################################################################
    //== KONSTRUKTORY A TOVÁRNÍ METODY =========================================

       /** Soukromy konstruktor bránící vytvoření instance. */
        private Correction() {}


    //== ABSTRAKTNÍ METODY =====================================================
    //== PŘÍSTUPOVÉ METODY VLASTNOSTÍ INSTANCÍ =================================
    //== OSTATNÍ NESOUKROMÉ METODY INSTANCÍ ====================================
    //== SOUKROMÉ A POMOCNÉ METODY TŘÍDY =======================================
    //== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ====================================
    //== INTERNÍ DATOVÉ TYPY ===================================================
    //== TESTY A METODA MAIN ===================================================
    }


///#############################################################################
///#############################################################################
///#############################################################################


    /*******************************************************************************
     * Výkonná třída implementující rozhraní {@code IIO} obsahuje sadu metod
     * pro jednoduchý vstup a výstup prostřednictvím dialogovýách oken
     * spolu s metodou zastavující běh programu na daný počet milisekund
     * a metodu převádějící texty na ASCII jednoduchým odstraněním diakritiky.
     */
    private static final class IOBěžné implements IIO
    {
    //== CONSTANT CLASS ATTRIBUTES =================================================
    //== VARIABLE CLASS ATTRIBUTES =================================================

        /** Pozice dialogových oken. */
        private static Point poziceOken = new Point(0,0);



    //== STATIC CONSTRUCTOR (CLASS INITIALIZER, STATIC INICITALIZING BLOCK) ======== 
    //== CONSTANT INSTANCE ATTRIBUTES ==============================================
    //== VARIABLE INSTANCE ATTRIBUTES ==============================================
    //== CLASS GETTERS AND SETTERS =================================================
    //== OTHER NON-PRIVATE CLASS METHODS ===========================================

        /***************************************************************************
         * Počká zadaný počet milisekund.
         * Na přerušení nijak zvlášť nereaguje - pouze skončí dřív.
         * Před tím však nastaví příznak, aby volající metoda poznala,
         * že vlákno bylo žádáno o přerušení.
         *
         * @param milisekund   Počet milisekund, po něž se má čekat.
         */
        @Override public void hold(int milisekund)
        {
            try {
                Thread.sleep(milisekund);
            }catch(InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }


        /***************************************************************************
         * Při splnění zadané podmínky otevře dialogové okno s nápisem KONEC
         * a po jeho zavření ukončí program.
         *
         * @param platí  Podmínka, po jejímž splnění se program ukončí
         */
        @Override public void endIf(boolean platí)
        {
            endIf(platí, null);
        }


        /***************************************************************************
         * Při splnění zadané podmínky otevře dialogové okno se zadanou zprávou
         * a po jeho zavření ukončí program.
         *
         * @param platí  Podmínka, po jejímž splnění se program ukončí
         * @param inform Zpráva vypisovaná v dialogovém okně. Je-li {@code null}
         *               nebo prázdný řetězec, vypíše <b>{@code KONEC}</b>.
         */
        @Override public void endIf(boolean platí, String zpráva)
        {
            if (platí) {
                if ((zpráva == null)  ||  (zpráva.equals(""))) {
                    zpráva = "KONEC";
                }
                inform(zpráva);
                System.exit(0);
            }
        }


        /***************************************************************************
         * Zbaví zadaný text diakritických znamének; současně ale odstraní také
         * všechny další znaky nespadající do tabulky ASCII.
         *
         * @param text Text určený k "odháčkování"
         * @return  "Odháčkovaný" text
         */
        @Override public String removeAccents(String text)
        {
            return Odháčkuj.text(text);
        }


        /***************************************************************************
         * Nastaví pozici příštího dialogového okna.
         *
         * @param x  Vodorovná souřadnice
         * @param y  Svislá souřadnice
         */
        @Override public void setDialogsPosition(int x, int y)
        {
            poziceOken = new Point(x, y);
            if (OPRAVOVAT) {
                poziceOken.x += INSETS_DIF.left;
                poziceOken.y += INSETS_DIF.top + INSETS_DIF.bottom;
            }
        }


        /***************************************************************************
         * Zobrazí dialogové okno se zprávou a umožní uživateli odpovědět
         * ANO nebo NE. Vrátí informaci o tom, jak uživatel odpověděl.
         * Neodpoví-li a zavře dialog, ukončí program.
         *
         * @param dotaz   Zobrazovaný text otázky.
         * @return <b>{@code true}</b> Odpověděl-li uživatel <b>ANO</b>,
         *         <b>{@code false}</b> odpověděl-li <b>NE</b>
         */
        @Override public boolean confirm(Object dotaz)
        {
            JOptionPane jop = new JOptionPane(
                                    dotaz,
                                    JOptionPane.QUESTION_MESSAGE,   //Message type
                                    JOptionPane.YES_NO_OPTION       //Option type
                                   );
            processJOP(jop);
            int answer = (Integer)jop.getValue();
            return (answer == JOptionPane.YES_OPTION);
        }


        /***************************************************************************
         * Zobrazí dialogové okno s výzvou k zadání reálné hodoty;
         * při zavření okna zavíracím tlačítkem ukončí aplikaci.
         *
         * @param výzva        Text, který se uživateli zobrazí.
         * @param doubleImpl   Implicitní hodnota.
         * @return Uživatelem zadaná hodnota, resp. potvrzená implicitní hodnota.
         */
        @Override public double enter(Object výzva, double doubleImpl)
        {
            return Double.parseDouble(enter(výzva, ""+doubleImpl).trim());
        }


        /***************************************************************************
         * Zobrazí dialogové okno s výzvou k zadání celočíselné hodoty;
         * při zavření okna nebo stisku tlačítka Cancel ukončí aplikaci.
         *
         * @param výzva     Text, který se uživateli zobrazí.
         * @param intImpl   Implicitní hodnota.
         * @return Uživatelem zadaná hodnota, resp. potvrzená implicitní hodnota.
         */
        @Override public int enter(Object výzva, int intImpl)
        {
            return Integer.parseInt(enter(výzva, ""+intImpl).trim());
        }


        /***************************************************************************
         * Zobrazí dialogové okno s výzvou k zadání textové hodoty;
         * při zavření okna nebo stisku tlačítka Cancel ukončí aplikaci.
         *
         * @param výzva        Text, který se uživateli zobrazí.
         * @param stringImpl   Implicitní hodnota.
         * @return Uživatelem zadaná hodnota, resp. potvrzená implicitní hodnota.
         */
        @Override public String enter(Object výzva, String stringImpl)
        {
            JOptionPane jop = new JOptionPane(
                                  výzva,
                                  JOptionPane.QUESTION_MESSAGE,   //Message type
                                  JOptionPane.DEFAULT_OPTION  //Option type - OK
                                 );
            jop.setWantsInput(true);
            jop.setInitialSelectionValue(stringImpl);
            processJOP(jop);
            String answer = jop.getInputValue().toString();
            return answer;
        }


        /***************************************************************************
         * Zobrazí dialogové okno se zprávou a počká, až je uživatel odklepne;
         * při zavření okna ukončí aplikaci.
         *
         * @param text   Zobrazovaný text.
         */
        @Override public void inform(Object text)
        {
            JOptionPane jop = new JOptionPane(
                              text,                            //Sended message
                              JOptionPane.INFORMATION_MESSAGE  //Message type
                             );
            processJOP(jop);
        }



    //##############################################################################
    //== CONSTUCTORS AND FACTORY METHODS ===========================================

        /***************************************************************************
         * Třída IO je knihovní třídou a proto není určena k tomu,
         * aby měla nějaké instance.
         */
        private IOBěžné() {}


    //== ABSTRACT METHODS ==========================================================
    //== INSTANCE GETTERS AND SETTERS ==============================================
    //== OTHER NON-PRIVATE INSTANCE METHODS ========================================
    //== PRIVATE AND AUXILIARY CLASS METHODS =======================================

        /***************************************************************************
         * Creates a dialog from the given {@link JOptionPane}, makes it non-modal
         * and waits for its closing leaving the entered value in the parameter's
         * attribute {@code value}. If the user closed the dialog
         * from the window's system menu, exit the whole application.
         *
         * @param jop
         */
        private static void processJOP(JOptionPane jop)
        {
            final int WAITING=0, CANCELLED=1;
            final Boolean[] USER = {true, false};

            final JDialog jd = jop.createDialog((JDialog)null, "Information");

            jd.addWindowListener(new WindowAdapter()
            {
                /** Set the information about closing the window from its
                 *  systme menu - the application will be cancelled. */
                @Override
                public void windowClosing(WindowEvent e) {
                    synchronized(USER) {
                        USER[CANCELLED] = true;
                        System.exit(1);
                    }
                }
                @Override
                public void windowDeactivated(WindowEvent e) {
                    poziceOken = jd.getLocation();
                    if (jd.isShowing()) {
                        return;
                    }else{
                        jd.dispose();
                        synchronized(USER) {
                            USER[WAITING] = false;
                            USER.notifyAll();
                        }
                    }
                }
             });

            jd.setModal(false);
            jd.setVisible(true);
            jd.setLocation(poziceOken);
            jd.toFront();
            jd.setAlwaysOnTop(true);
    //        jd.setAlwaysOnTop(false);

            //Waiting until the user answers or closes the dialog
            synchronized(USER) {
                while (USER[WAITING]) {
                    try {
                        USER.wait();
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        }



    //== PRIVATE AND AUXILIARY INSTANCE METHODS ====================================
    //== EMBEDDED TYPES AND INNER CLASSES ==========================================

        /***************************************************************************
         * Třída {@code Odháčkuj_RUP} je knihovní třídou poskytující metodu na
         * odstranění diakritiky ze zadaného textu a následné převedení všech znaků,
         * jejichž kód je stále větší než 127, na příslušné kódové
         * únikové posloupnosti (escape sekvence).
         */
        private static class Odháčkuj
        {
        //== KONSTANTNÍ ATRIBUTY TŘÍDY =============================================

            /** Mapa s převody znaků do ASCII. */
            private static final Map<Character,String> PŘEVOD =
                                                new HashMap<Character, String>(64);
        //== PROMĚNNÉ ATRIBUTY TŘÍDY ===============================================
        //== STATICKÝ INICIALIZAČNÍ BLOK - STATICKÝ KONSTRUKTOR ====================
            static {
                String[][] dvojice = {

                    {"Á", "A"},  {"á", "a"},    {"Ä", "AE"}, {"ä", "ae"},
                    {"Č", "C"},  {"č", "c"},
                    {"Ď", "D"},  {"ď", "d"},    {"Ë", "E"},  {"ë", "e"},
                    {"É", "E"},  {"é", "e"},
                    {"Ě", "E"},  {"ě", "e"},
                    {"Í", "I"},  {"í", "i"},    {"Ï", "IE"}, {"ï", "ie"},
                    {"Ĺ", "L"},  {"ĺ", "l"},    {"Ľ", "L"},  {"ľ", "l"},
                    {"Ň", "N"},  {"ň", "n"},
                    {"Ó", "O"},  {"ó", "o"},    {"Ö", "OE"}, {"ö", "oe"},
                    {"Ô", "O"},  {"ô", "o"},
                    {"Ŕ", "R"},  {"ŕ", "r"},    {"Ř", "R"},  {"ř", "r"},
                    {"Š", "S"},  {"š", "s"},
                    {"Ť", "T"},  {"ť", "t"},
                    {"Ú", "U"},  {"ú", "u"},    {"Ü", "UE"}, {"ü", "ue"},
                    {"Ů", "U"},  {"ů", "u"},
                    {"Ý", "Y"},  {"ý", "y"},    {"Ÿ", "YE"}, {"ÿ", "ye"},
                    {"Ž", "Z"},  {"ž", "z"},
                    {"ß", "ss"},
                    {"«", "<<"}, {"»", ">>"},
    //                {"",""},
                };
                for (String[] ss : dvojice) {
                    PŘEVOD.put(new Character(ss[0].charAt(0)),  ss[1]);
                }
                dvojice = null;
            }



        //== KONSTANTNÍ ATRIBUTY INSTANCÍ ==========================================
        //== PROMĚNNÉ ATRIBUTY INSTANCÍ ============================================
        //== PŘÍSTUPOVÉ METODY VLASTNOSTÍ TŘÍDY ====================================
        //== OSTATNÍ NESOUKROMÉ METODY TŘÍDY =======================================

            /***********************************************************************
             * Zbaví zadaný text diakritických znamének - <b>POZOR</b> -
             * Spolu s nimi odstraní také všechny znaky s kódem větším než 127.
             *
             * @param text Text určený k "odháčkování"
             * @return  "Odháčkovaný" text
             */
            public static String text(CharSequence text)
            {
                final int DÉLKA = text.length();
                final StringBuilder sb = new StringBuilder(DÉLKA);
                for (int i = 0;   i < DÉLKA;   i++) {
                    char c = text.charAt(i);
                    if (c < 128) {
                        sb.append(c);
                    }else if (PŘEVOD.containsKey(c)) {
                        sb.append(PŘEVOD.get(c));
                    }else {
                        sb.append(rozepiš(c));
                    }
                }
                return sb.toString();
            }



        //##########################################################################
        //== KONSTRUKTORY A TOVÁRNÍ METODY =========================================

           /** Soukromy konstruktor bránící vytvoření instance. */
            private Odháčkuj() {}


        //== ABSTRAKTNÍ METODY =====================================================
        //== PŘÍSTUPOVÉ METODY VLASTNOSTÍ INSTANCÍ =================================
        //== OSTATNÍ NESOUKROMÉ METODY INSTANCÍ ====================================
        //== SOUKROMÉ A POMOCNÉ METODY TŘÍDY =======================================

            /***********************************************************************
             * Rozepíše zadaný znak do příslušné ńikové k´dové posloupnosti.
             *
             * @param c Převáděný znak
             * @return Text ve formátu \\uXXXX
             */
            private static String rozepiš(char c) {
                return String.format("\\u%04x", (int)c);
            }



        //== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ====================================
        //== INTERNÍ DATOVÉ TYPY ===================================================
        //== TESTY A METODA MAIN ===================================================
        }



    //== TESTING CLASSES AND METHODS ===============================================
    }


///#############################################################################
///#############################################################################
///#############################################################################


    /*******************************************************************************
     * Testovací implementace rozhraní {@code IIO}, která ignoruje všechny volání
     * metod, pouze zaznamenává počet jejich volání.
     *
     * @author   Vladimír Oraný
     */
    private static final class IOTestovací implements IIO
    {
    //== CONSTANT CLASS ATTRIBUTES =================================================
    //== VARIABLE CLASS ATTRIBUTES =================================================
    //== STATIC CONSTRUCTOR (CLASS INITIALIZER, STATIC INICITALIZING BLOCK) ======== 
    //== CONSTANT INSTANCE ATTRIBUTES ==============================================
    //== VARIABLE INSTANCE ATTRIBUTES ==============================================
    //== CLASS GETTERS AND SETTERS =================================================
    //== OTHER NON-PRIVATE CLASS METHODS ===========================================

        @Override public void hold(int milisekund) {
            přidejVoláníMetody("čekej_int");
        }
        @Override public void endIf(boolean platí) {
            přidejVoláníMetody("konecKdyž_boolean");
        }
        @Override public void endIf(boolean platí, String zpráva) {
            přidejVoláníMetody("konecKdyž_boolean_String");
        }
        @Override public String removeAccents(String text) {
            přidejVoláníMetody("odháčkuj_String");
            return IOBěžné.Odháčkuj.text(text);
        }
        @Override public void setDialogsPosition(int x, int y) {
            přidejVoláníMetody("oknaNa_int_int");
        }
        @Override public boolean confirm(Object dotaz) {
            přidejVoláníMetody("souhlas_Object");
            return true;
        }
        @Override public double enter(Object výzva, double doubleImpl) {
            přidejVoláníMetody("zadej_Object_double");
            return doubleImpl;
        }
        @Override public int enter(Object výzva, int intImpl) {
            přidejVoláníMetody("zadej_Object_int");
            return intImpl;
        }
        @Override public String enter(Object výzva, String stringImpl) {
            přidejVoláníMetody("zadej_Object_String");
            return stringImpl;
        }
        @Override public void inform(Object text) {
            přidejVoláníMetody("zpráva_Object");
        }



    //##############################################################################
    //== CONSTUCTORS AND FACTORY METHODS ===========================================

        /***************************************************************************
         * Třída {@code TestovacíIO} bude viditelná
         * ouze v rámci třídy {@code IO}.
         */
        private IOTestovací() {}


    //== ABSTRACT METHODS ==========================================================
    //== INSTANCE GETTERS AND SETTERS ==============================================
    //== OTHER NON-PRIVATE INSTANCE METHODS ========================================
    //== PRIVATE AND AUXILIARY CLASS METHODS =======================================

        /***************************************************************************
         * Zaznamená volání metody do systémových proměnných. Systémové proměnné
         * začánají na <code>rup.io.method.</code> a následuje označení metody
         * ve tvaru <code>jménoMetody_typParametru1_typParametru2</code>
         *
         * @param metoda   Označení metody.
         */
        private static void přidejVoláníMetody(String metoda)
        {
            String kód = "rup.io.method." + metoda;
            String hodnota = System.getProperty(kód, "0");
            int počet = Integer.valueOf(hodnota);
            počet++;
            System.setProperty(kód, "" + počet);
        }
    //== PRIVATE AND AUXILIARY INSTANCE METHODS ====================================
    //== EMBEDDED TYPES AND INNER CLASSES ==========================================
    //== TESTING CLASSES AND METHODS ===============================================
    }


///#############################################################################
///#############################################################################
///#############################################################################


//== TESTING CLASSES AND METHODS ===============================================
    }



///#############################################################################
///#############################################################################
///#############################################################################


    /*******************************************************************************
     * Rozhraní {@code IIO} deklaruje kompletní sadu metod
     * implementovaných třídou {@code IO}.
     * Představuje společného rodiče výkonné a testovací třídy,
     * tj. třídy {@code IOBěžné} a třídy {@code IOTestovací}.
     */
    interface IIO
    {
    //== CONSTANTS =================================================================
    //== DECLARED METHODS ==========================================================

        public void    hold              (int milisekund);
        public void    endIf             (boolean platí);
        public void    endIf             (boolean platí, String zpráva);
        public String  removeAccents     (String text);
        public void    setDialogsPosition(int x, int y);
        public boolean confirm           (Object dotaz);
        public double  enter             (Object výzva, double doubleImpl);
        public int     enter             (Object výzva, int intImpl);
        public String  enter             (Object výzva, String stringImpl);
        public void    inform            (Object text);

    //== INHERITED METHODS =========================================================
    //== EMBEDDED TYPES AND INNER CLASSES ==========================================
    }

//%%- ---- Start of the ovejumped text with closing of the envelope ----
////////////////////////////////////////////////////////////////////////////////
//== TESTING CLASSES AND METHODS ===============================================

    /***************************************************************************
     * Test method.
     */
    public static void test()
    {
//        Run.tests(Test.class,
//                new TearDown(),
//                "testFixture",
//                "");
        IO.inform("Až se pokocháš, stiskni OK");
        System.exit(0);
    }
    /** @param args Parametry příkazového řádku - nepoužívané. */
    public static void main(String[] args)  {  test();  }
}
